// test_api_validation.c
#include "test_framework.h"
#include "../hisi_l0_mem_pool.h"
#include "test_common.h"
#include "test_registration.h"

/**
 * test_l0_kmalloc_parameter_validation - Tests parameter validation for l0_kmalloc
 * 
 * This test verifies:
 * 1. Proper handling of zero size allocations (should return NULL)
 * 2. Proper handling of negative size allocations (should return NULL)
 * 3. Valid node ID handling
 * 4. Invalid negative node ID handling (should return NULL)
 * 5. Excessive node ID handling (should return NULL)
 * 
 * Tests robust error handling for various invalid input parameters
 */
static int test_l0_kmalloc_parameter_validation(struct seq_file *m)
{
    void *ptr;
    int passed = 0, total = 0;
    struct test_context *ctx = get_test_context();
    
    // Test 1: Valid parameters
    total++;
    ptr = l0_kmalloc(128, ctx->test_node_id);
    if (ptr) {
        l0_kfree(ptr);
        TEST_PASS(m, "l0_kmalloc with valid parameters works correctly");
        passed++;
    } else {
        TEST_FAIL(m, "l0_kmalloc with valid parameters failed");
    }
    
    // Test 2: Zero size
    total++;
    ptr = l0_kmalloc(0, ctx->test_node_id);
    if (ptr == NULL) {
        TEST_PASS(m, "l0_kmalloc correctly rejects zero size");
        passed++;
    } else {
        TEST_FAIL(m, "l0_kmalloc should return NULL for zero size");
        l0_kfree(ptr);
    }
    
    // Test 3: Negative size
    total++;
    ptr = l0_kmalloc(-1, ctx->test_node_id);
    if (ptr == NULL) {
        TEST_PASS(m, "l0_kmalloc correctly rejects negative size");
        passed++;
    } else {
        TEST_FAIL(m, "l0_kmalloc should return NULL for negative size");
        l0_kfree(ptr);
    }
    
    // Test 4: Valid node ID
    total++;
    ptr = l0_kmalloc(64, 0);
    if (ptr) {
        l0_kfree(ptr);
        TEST_PASS(m, "l0_kmalloc with valid node ID works correctly");
        passed++;
    } else {
        TEST_FAIL(m, "l0_kmalloc with valid node ID failed");
    }
    
    // Test 5: Invalid negative node ID
    total++;
    ptr = l0_kmalloc(64, -1);
    if (ptr == NULL) {
        TEST_PASS(m, "l0_kmalloc correctly rejects negative node ID");
        passed++;
    } else {
        TEST_FAIL(m, "l0_kmalloc should return NULL for negative node ID");
        l0_kfree(ptr);
    }
    
    // Test 6: Excessive node ID
    total++;
    ptr = l0_kmalloc(64, MAX_NUMA_NODES + 1);
    if (ptr == NULL) {
        TEST_PASS(m, "l0_kmalloc correctly rejects excessive node ID");
        passed++;
    } else {
        TEST_FAIL(m, "l0_kmalloc should return NULL for excessive node ID");
        l0_kfree(ptr);
    }
    
    TEST_END(m, "l0_kmalloc parameter validation: %d/%d tests passed", passed, total);
    return (passed == total) ? 0 : -1;
}

/**
 * test_l0_kfree_parameter_validation - Tests parameter validation for l0_kfree
 * 
 * This test verifies:
 * 1. Safe handling of NULL pointer freeing (should not crash)
 * 2. Proper freeing of valid allocated memory
 * 3. Behavior with double-free operations
 * 
 * Tests robustness against invalid free operations
 */
static int test_l0_kfree_parameter_validation(struct seq_file *m)
{
    int passed = 0, total = 0;
    void *ptr;
    
    // Test 1: Freeing NULL pointer (should not crash)
    total++;
    l0_kfree(NULL);
    TEST_PASS(m, "l0_kfree correctly handles NULL pointer");
    passed++;
    
    // Test 2: Freeing valid pointer
    total++;
    ptr = l0_kmalloc(128, 0);
    if (ptr) {
        l0_kfree(ptr);
        TEST_PASS(m, "l0_kfree works with valid pointer");
        passed++;
    } else {
        TEST_FAIL(m, "Could not allocate memory for l0_kfree test");
    }
    
    // Test 3: Double free (should be handled gracefully)
    total++;
    // Try to allocate another pointer for double-free testing
    ptr = l0_kmalloc(128, 0);
    if (ptr) {
        l0_kfree(ptr); // First free
        l0_kfree(ptr); // Double free - should not crash
        TEST_PASS(m, "l0_kfree double free test completed without crashing");
        passed++;
    } else {
        TEST_FAIL(m, "Could not allocate memory for double free test");
    }
    
    TEST_END(m, "l0_kfree parameter validation: %d/%d tests passed", passed, total);
    return (passed == total) ? 0 : -1;
}

/**
 * test_l0_alloc_pages_parameter_validation - Tests parameter validation for l0_alloc_pages
 * 
 * This test verifies:
 * 1. Proper handling of zero size page allocations (should return NULL)
 * 2. Proper handling of negative size page allocations (should return NULL)
 * 3. Valid node ID handling for page allocation
 * 4. Invalid negative node ID handling (should return NULL)
 * 5. Excessive node ID handling (should return NULL)
 * 
 * Tests robust error handling for page allocation API
 */
static int test_l0_alloc_pages_parameter_validation(struct seq_file *m)
{
    struct page *page;
    int passed = 0, total = 0;
    struct test_context *ctx = get_test_context();
    
    // Test 1: Valid parameters
    total++;
    page = l0_alloc_pages(1, ctx->test_node_id);
    if (page) {
        l0_free_pages(page);
        TEST_PASS(m, "l0_alloc_pages with valid parameters works correctly");
        passed++;
    } else {
        TEST_FAIL(m, "l0_alloc_pages with valid parameters failed");
    }
    
    // Test 2: Zero size
    total++;
    page = l0_alloc_pages(0, ctx->test_node_id);
    if (page == NULL) {
        TEST_PASS(m, "l0_alloc_pages correctly rejects zero size");
        passed++;
    } else {
        TEST_FAIL(m, "l0_alloc_pages should return NULL for zero size");
        l0_free_pages(page);
    }
    
    // Test 3: Negative size
    total++;
    page = l0_alloc_pages(-1, ctx->test_node_id);
    if (page == NULL) {
        TEST_PASS(m, "l0_alloc_pages correctly rejects negative size");
        passed++;
    } else {
        TEST_FAIL(m, "l0_alloc_pages should return NULL for negative size");
        l0_free_pages(page);
    }
    
    // Test 4: Valid node ID
    total++;
    page = l0_alloc_pages(1, 0);
    if (page) {
        l0_free_pages(page);
        TEST_PASS(m, "l0_alloc_pages with valid node ID works correctly");
        passed++;
    } else {
        TEST_FAIL(m, "l0_alloc_pages with valid node ID failed");
    }
    
    // Test 5: Invalid negative node ID
    total++;
    page = l0_alloc_pages(1, -1);
    if (page == NULL) {
        TEST_PASS(m, "l0_alloc_pages correctly rejects negative node ID");
        passed++;
    } else {
        TEST_FAIL(m, "l0_alloc_pages should return NULL for negative node ID");
        l0_free_pages(page);
    }
    
    // Test 6: Excessive node ID
    total++;
    page = l0_alloc_pages(1, MAX_NUMA_NODES + 1);
    if (page == NULL) {
        TEST_PASS(m, "l0_alloc_pages correctly rejects excessive node ID");
        passed++;
    } else {
        TEST_FAIL(m, "l0_alloc_pages should return NULL for excessive node ID");
        l0_free_pages(page);
    }
    
    TEST_END(m, "l0_alloc_pages parameter validation: %d/%d tests passed", passed, total);
    return (passed == total) ? 0 : -1;
}

/**
 * test_l0_free_pages_parameter_validation - Tests parameter validation for l0_free_pages
 * 
 * This test verifies:
 * 1. Safe handling of NULL page pointer freeing (should not crash)
 * 2. Proper freeing of valid allocated pages
 * 
 * Tests robustness against invalid page free operations
 */
static int test_l0_free_pages_parameter_validation(struct seq_file *m)
{
    int passed = 0, total = 0;
    struct page *page;
    
    // Test 1: Freeing NULL page pointer (should not crash)
    total++;
    l0_free_pages(NULL);
    TEST_PASS(m, "l0_free_pages correctly handles NULL page pointer");
    passed++;
    
    // Test 2: Freeing valid page
    total++;
    page = l0_alloc_pages(1, 0);
    if (page) {
        l0_free_pages(page);
        TEST_PASS(m, "l0_free_pages works with valid page");
        passed++;
    } else {
        TEST_FAIL(m, "Could not allocate page for l0_free_pages test");
    }
    
    TEST_END(m, "l0_free_pages parameter validation: %d/%d tests passed", passed, total);
    return (passed == total) ? 0 : -1;
}

/**
 * test_api_edge_cases - Tests API behavior at boundary conditions
 * 
 * This test verifies:
 * 1. Handling of very large allocation sizes (1GB)
 * 2. Behavior at MAX_FIX_ALLOCATOR_SIZE boundary
 * 3. Behavior just above MAX_FIX_ALLOCATOR_SIZE (transitions to flex_allocator)
 * 4. Very small allocation sizes (1 byte)
 * 5. Non-page-aligned page allocations
 * 
 * Tests edge cases and boundary conditions of the API
 */
static int test_api_edge_cases(struct seq_file *m)
{
    void *ptr;
    int passed = 0, total = 0;
    struct test_context *ctx = get_test_context();
    
    // Test 1: Very large allocation size
    total++;
    ptr = l0_kmalloc(1UL << 30, ctx->test_node_id); // 1GB allocation
    if (ptr == NULL) {
        TEST_PASS(m, "l0_kmalloc correctly rejects very large allocation");
        passed++;
    } else {
        TEST_INFO(m, "l0_kmalloc with very large size returned pointer (may be acceptable)");
        l0_kfree(ptr);
        passed++; // Acceptable
    }
    
    // Test 2: Boundary size at MAX_FIX_ALLOCATOR_SIZE
    total++;
    ptr = l0_kmalloc(MAX_FIX_ALLOCATOR_SIZE, ctx->test_node_id);
    if (ptr) {
        l0_kfree(ptr);
        TEST_PASS(m, "l0_kmalloc works at MAX_FIX_ALLOCATOR_SIZE boundary");
        passed++;
    } else {
        TEST_FAIL(m, "l0_kmalloc at MAX_FIX_ALLOCATOR_SIZE boundary failed");
    }
    
    // Test 3: Boundary size just above MAX_FIX_ALLOCATOR_SIZE (should use flex_allocator)
    total++;
    ptr = l0_kmalloc(MAX_FIX_ALLOCATOR_SIZE + 1, ctx->test_node_id);
    if (ptr) {
        l0_kfree(ptr);
        TEST_PASS(m, "l0_kmalloc works just above MAX_FIX_ALLOCATOR_SIZE boundary");
        passed++;
    } else {
        TEST_FAIL(m, "l0_kmalloc just above MAX_FIX_ALLOCATOR_SIZE boundary failed");
    }
    
    // Test 4: Very small allocation size
    total++;
    ptr = l0_kmalloc(1, ctx->test_node_id);
    if (ptr) {
        l0_kfree(ptr);
        TEST_PASS(m, "l0_kmalloc works with very small allocation");
        passed++;
    } else {
        TEST_FAIL(m, "l0_kmalloc with very small size failed");
    }
    
    TEST_END(m, "API edge cases: %d/%d tests passed", passed, total);
    return (passed == total) ? 0 : -1;
}

/**
 * test_double_free_handling - Tests handling of double free operations
 * 
 * This test verifies:
 * 1. Safe handling of double free operations
 * 2. System stability when double freeing memory
 * 
 * Tests robustness against double free operations
 */
static int test_double_free_handling(struct seq_file *m)
{
    struct test_context *ctx = get_test_context();
    void *ptr;
    int passed = 0, total = 0;
    
    total++;
    ptr = l0_kmalloc(128, ctx->test_node_id);
    if (ptr) {
        l0_kfree(ptr);
        // Double free - should not crash
        l0_kfree(ptr);
        TEST_PASS(m, "Double free operation handled safely");
        passed++;
    } else {
        TEST_FAIL(m, "Could not allocate memory for double free test");
    }
    
    TEST_END(m, "Double free handling tests: %d/%d passed", passed, total);
    return (passed == total) ? 0 : -1;
}

/**
 * test_free_unallocated_memory - Tests freeing unallocated memory pointers
 * 
 * This test verifies:
 * 1. Safe handling of freeing unallocated memory
 * 2. System stability when freeing random pointers
 * 
 * Tests robustness against freeing unallocated memory
 */
static int test_free_unallocated_memory(struct seq_file *m)
{
    int passed = 0, total = 0;
    char dummy_data[128];
    void *fake_ptr = dummy_data;
    
    total++;
    // Freeing a pointer that was not allocated by our allocator
    l0_kfree(fake_ptr);
    TEST_PASS(m, "Freeing unallocated memory handled safely");
    passed++;
    
    TEST_END(m, "Free unallocated memory tests: %d/%d passed", passed, total);
    return (passed == total) ? 0 : -1;
}

// Export test cases
static struct test_case test_api_validation_cases[] = {
    {"l0_kmalloc Parameter Validation", test_l0_kmalloc_parameter_validation},
    {"l0_kfree Parameter Validation", test_l0_kfree_parameter_validation},
    {"l0_alloc_pages Parameter Validation", test_l0_alloc_pages_parameter_validation},
    {"l0_free_pages Parameter Validation", test_l0_free_pages_parameter_validation},
    {"API Edge Cases", test_api_edge_cases},
    {"Double Free Handling", test_double_free_handling},
    {"Free Unallocated Memory", test_free_unallocated_memory},
};

DECLARE_TEST_MODULE(api_validation, test_api_validation_cases)